package utils;

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @program: postgirl-client
 * @description: 对象工具
 * @author: Cheng Zhi
 * @create: 2023-07-31 14:08
 **/
public class ObjUtils {

    private static JefLog jefLog = new JefLog(ObjUtils.class);

    /**
     * 获取一个Collection对象的泛型类
     * @param obj
     * @return
     */
    public static Class getGenericsClass(Object obj) {

        String typeName = getGenericsTypeName(obj);
        Class<?> aClass = null;
        try {
            aClass = Class.forName(typeName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        return aClass;
    }

    /**
     * 获取指定类全名的Class对象
     * @param typeName
     * @return
     */
    public static Class getClass(String typeName) {

        Class<?> aClass = null;
        try {
            aClass = Class.forName(typeName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        return aClass;
    }

    public static String getGenericsTypeName(Object obj) {

        String typeName = "";
        try {
            Type clazz = obj.getClass().getGenericSuperclass();
            if (clazz instanceof ParameterizedType) {
                ParameterizedType pt = (ParameterizedType)clazz;
                Type actualTypeArgument = pt.getActualTypeArguments()[0];
                typeName = actualTypeArgument.getTypeName();
                jefLog.debug("获取到的泛型类：" + typeName);
            }
        } catch (Exception exceptin) {
            jefLog.error("获取泛型失败，或许是没有泛型：" + obj.getClass().getName());
        }

        return typeName;
    }


    /**
     * 获取所有对象属性名称
     * @param o
     * @return
     */
    public static String[] getFiledNames(Object o) {
        Field[] fields=o.getClass().getDeclaredFields();
        String[] fieldNames=new String[fields.length];
        for(int i=0;i<fields.length;i++){
            fieldNames[i]=fields[i].getName();
        }
        return fieldNames;
    }

    /**
     * 获取所有对象属性名称(下划线命名法)
     * @param o
     * @return
     */
    public static Map<String, Class<?>> getFiledUnderNamesAndType(Object o) {
        Field[] fields=o.getClass().getDeclaredFields();
        Map<String, Class<?>> fieldNameAndType = new HashMap<>();
        for(int i=0;i<fields.length;i++){

            // 获取修饰符号
            int modifiers = fields[i].getModifiers();
            // 如果是final修饰的一般不需要get值
            if (Modifier.isFinal(modifiers)) {
                continue;
            }

            Class<?> type = fields[i].getType();
            fieldNameAndType.put(camel2under(fields[i].getName()), type);
        }
        return fieldNameAndType;
    }

    /**
     * 基本数据类型转换为普通类型
     * @param type
     * @return
     */
    public static Class<?> baseType2Wrapper(Class<?> type) {

        try {
            String name = type.getName();
            switch (name) {
                case "int":
                    return Class.forName("java.lang.Integer");
                case "long":
                    return Class.forName("java.lang.Long");
                case "short":
                    return Class.forName("java.lang.Short");
                case "char":
                    return Class.forName("java.lang.Character");
                case "byte":
                    return Class.forName("java.lang.Byte");
                case "boolean":
                    return Class.forName("java.lang.Boolean");
                case "float":
                    return Class.forName("java.lang.Float");
                case "double":
                    return Class.forName("java.lang.Double");
                default:
                    return type;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return type;
    }
    /**
     * 获取字段名和值
     * @param o
     * @param map
     */
    public static void getFieldNameAndValue(Object o, Map<String, Object> map) {

        if (o instanceof Map) {

            for (Object keyObject : ((Map) o).keySet()) {
                Object value = ((Map) o).get(keyObject);

                if (value instanceof ArrayList) {
                    for (Object listObj : (ArrayList)value) {
                        getFieldNameAndValue(listObj, map);
                    }
                }
            }
        } else {

            Field[] fields=o.getClass().getDeclaredFields();
            String[] fieldNames=new String[fields.length];
            for(int i=0;i<fields.length;i++){
                // 获取修饰符号
                int modifiers = fields[i].getModifiers();
                // 如果是final修饰的一般不需要get值
                if (Modifier.isFinal(modifiers)) {
                    continue;
                }
                fieldNames[i]=fields[i].getName();
            }
            try {
                for (String fieldName : fieldNames) {
                    if (fieldName == null) {
                        // 由于上面的循环判断了修饰符，过滤了一部分字段，所以这里会出现为null的情况
                        continue;
                    }
                    Method method = o.getClass().getMethod("get" + returnFirstCapital(fieldName));
                    Object invoke = method.invoke(o);
                    if (invoke != null) {
                        map.put(camel2under(fieldName), invoke);
                    }
                }
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 为对象设置参数值
     * @param o    目标对象
     * @param map   字段：value, 类型从常量中获取
     */
    public static void setFieldForObj(Object o, Map<String, Object> map) {

        if (o instanceof Map) {

            for (Object keyObject : ((Map) o).keySet()) {
                Object value = ((Map) o).get(keyObject);

                if (value instanceof ArrayList) {
                    for (Object listObj : (ArrayList)value) {
                        setFieldForObj(listObj, map);
                    }
                }
            }
        } else {

            Field[] fields=o.getClass().getDeclaredFields();
            Map<String, Class<?>> fieldNameAndType = new HashMap<>();
            for(int i=0;i<fields.length;i++){
                // 获取修饰符号
                int modifiers = fields[i].getModifiers();
                // 如果是final修饰的一般不需要get值
                if (Modifier.isFinal(modifiers)) {
                    continue;
                }
                fieldNameAndType.put(fields[i].getName(), fields[i].getType());
            }
            try {
                for (String fieldName : fieldNameAndType.keySet()) {
                    if (fieldName == null) {
                        // 由于上面的循环判断了修饰符，过滤了一部分字段，所以这里会出现为null的情况
                        continue;
                    }
                    Method method = o.getClass().getMethod("set" + returnFirstCapital(fieldName), fieldNameAndType.get(fieldName));
                    Object invoke = method.invoke(o, map.get(camel2under(fieldName)));
                }
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 为对象设置参数值
     * @param entity    目标对象
     * @param map   字段：value, 类型从常量中获取 ABC_BCD:12
     * @param fieldNameAndType 字段：类型 ABC_BCD:java.lang.String
     */
    public static Object setFieldForObj(Object entity, Map<String, Object> map, Map<String, Class<?>> fieldNameAndType) throws IllegalAccessException, InstantiationException {

        Object o = entity.getClass().newInstance();
        if (o instanceof Map) {

            for (Object keyObject : ((Map) o).keySet()) {
                Object value = ((Map) o).get(keyObject);

                if (value instanceof ArrayList) {
                    for (Object listObj : (ArrayList)value) {
                        setFieldForObj(listObj, map);
                    }
                }
            }
        } else {

            try {
                for (String fieldName : fieldNameAndType.keySet()) {
                    if (fieldName == null) {
                        // 由于上面的循环判断了修饰符，过滤了一部分字段，所以这里会出现为null的情况
                        continue;
                    }
                    Class<?> aClass = fieldNameAndType.get(fieldName);
                    Method method = o.getClass().getMethod("set" + returnFirstCapital(under2camel(fieldName)), aClass);
                    Object valueObj = map.get(camel2under(fieldName));
                    Object invoke = method.invoke(o,valueObj);
                }
            } catch(Exception e) {
                e.printStackTrace();
            }
        }

        return o;
    }


    /**
     * 将驼峰命名转换为下划线命名
     * @param c
     * @return
     */
    public static String camel2under(String c) {
        String separator = "_";
        c = c.replaceAll("([a-z])([A-Z])", "$1"+separator+"$2").toUpperCase();
        return c;
    }

    /**
     * 将下划线命名转换为驼峰命名
     * @param c
     * @return
     */
    public static String under2camel(String c) {

        c = c.toLowerCase();
        Pattern linePattern = Pattern.compile("_(\\w)");
        Matcher matcher = linePattern.matcher(c);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
        }
        matcher.appendTail(sb);

        return sb.toString();
    }
    /**
     * 判断字符串首字母是否为大写，如果不是转化为大写
     * @param str
     * @return
     */
    public static String returnFirstCapital(String str) {
        if (str.charAt(0) >= 'A' && str.charAt(0) <= 'Z') {
            return str;
        }
        char[] ch = str.toCharArray();
        ch[0] -= 32;
        return String.valueOf(ch);
    }
}
